﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Windows.Forms;

namespace Juggler
{
    abstract class Crawler: ICrawler
    {
        protected Resolution _ScreenResolution;
        protected double _ScreenRatio;
        protected string _SaveLocation;
        protected Action<UpdateData> _Callback;
        protected CrawlStatus _CrawlStatus = Juggler.CrawlStatus.Stopped;

        protected static byte[][] bytes = new byte[][] {
                new byte[] {85,0,115,0,101,0,114,0,65,0,103,0,101,0,110,0,116,0},
                new byte[] {77,0,111,0,122,0,105,0,108,0,108,0,97,0,47,0,52,0,46,0,48,0,32,0,40,0,99,0,111,0,109,0,112,0,97,0,116,0,105,0,98,0,108,0,101,0,59,0,32,0,77,0,83,0,73,0,69,0,32,0,55,0,46,0,48,0,59,0,32,0,87,0,105,0,110,0,100,0,111,0,119,0,115,0,32,0,78,0,84,0,32,0,54,0,46,0,49,0,59,0,32,0,84,0,114,0,105,0,100,0,101,0,110,0,116,0,47,0,52,0,46,0,48,0,59,0,32,0,83,0,76,0,67,0,67,0,50,0,59,0,32,0,46,0,78,0,69,0,84,0,32,0,67,0,76,0,82,0,32,0,50,0,46,0,48,0,46,0,53,0,48,0,55,0,50,0,55,0,59,0,32,0,46,0,78,0,69,0,84,0,32,0,67,0,76,0,82,0,32,0,51,0,46,0,53,0,46,0,51,0,48,0,55,0,50,0,57,0,59,0,32,0,46,0,78,0,69,0,84,0,32,0,67,0,76,0,82,0,32,0,51,0,46,0,48,0,46,0,51,0,48,0,55,0,50,0,57,0,59,0,32,0,77,0,101,0,100,0,105,0,97,0,32,0,67,0,101,0,110,0,116,0,101,0,114,0,32,0,80,0,67,0,32,0,54,0,46,0,48,0,59,0,32,0,46,0,78,0,69,0,84,0,32,0,67,0,76,0,82,0,32,0,49,0,46,0,49,0,46,0,52,0,51,0,50,0,50,0,59,0,32,0,73,0,110,0,102,0,111,0,80,0,97,0,116,0,104,0,46,0,50,0,59,0,32,0,77,0,83,0,45,0,82,0,84,0,67,0,32,0,76,0,77,0,32,0,56,0,41,0},
                new byte[] {65,0,99,0,99,0,101,0,112,0,116,0},
                new byte[] {42,0,47,0,42,0},
                new byte[] {72,0,101,0,97,0,100,0,101,0,114,0,115,0},
                new byte[] {65,0,100,0,100,0},
                new byte[] {65,0,99,0,99,0,101,0,112,0,116,0,45,0,76,0,97,0,110,0,103,0,117,0,97,0,103,0,101,0},
                new byte[] {101,0,110,0,45,0,85,0,83,0}
            };


        public abstract void StartDownloading(Resolution ScreenResolution, string SaveLocation, int NumberOfThreads, Action<UpdateData> callback);
        public abstract void StopDownloading();
        public abstract CrawlStatus CrawlStatus();

        public Resolution[] GetResolutions()
        {
            //Create a list of different resolutions.
            List<Resolution> myResolutions = new List<Resolution>();
            int TotalScreenWidth, MaxScreenHeight;

            //Loop through each display and get the individual bounds
            Screen[] screens = Screen.AllScreens;
            foreach (System.Windows.Forms.Screen NewScreen in screens)
            {
                myResolutions.Add(new Resolution(NewScreen.Bounds.Width, NewScreen.Bounds.Height, ResolutionType.Any));
            }

            //Get the biggest size possible dependant on sum of widths and max height
            if (screens.Count() > 1)
            {
                TotalScreenWidth = screens.Sum(screen => screen.Bounds.Width);
                MaxScreenHeight = screens.Max(screen => screen.Bounds.Height);
                myResolutions.Add(new Resolution(TotalScreenWidth, MaxScreenHeight, ResolutionType.Any));
            }

            return myResolutions.ToArray();

        }

        protected static Stream GetWebStream(Uri url)
        {
            HttpWebRequest request;
            HttpWebResponse response;
            // Create a request for the URL.
            request = (HttpWebRequest)WebRequest.Create(url);

            DoIt(request);

            // Get the response.
            try
            {
                response = (HttpWebResponse)request.GetResponse(); //WebException
            }
            catch (WebException)
            {
                return null;
            }
            
            // Return the stream containing content returned from the server.
            return response.GetResponseStream();

        }

        private static void DoIt(HttpWebRequest r)
        {

            Type t = r.GetType();
            t.GetProperty(Value(0)).SetValue(r, Value(1), null);
            t.GetProperty(Value(2)).SetValue(r, Value(3), null);

            object o = t.GetProperty(Value(4)).GetValue(r, null);
            o.GetType().GetMethod(Value(5), new Type[] { typeof(string), typeof(string) }).Invoke(o, new string[] { Value(6), Value(7) });
        }

        private static string Value(int i)
        {
            return Encoding.Unicode.GetString(bytes[i]);
        }

        protected static void SaveImage(Stream readStream, string saveLocation, string photoTitle, Action<UpdateData> _Callback)
        {
            string targetFile = GetImageSavePath(saveLocation, photoTitle);

            if(File.Exists(targetFile))
            {
                _Callback(new UpdateData(EventType.ItemUpdate,photoTitle,ImageStatus.Skipped));
                return;
            }

            string tempLocation = Environment.GetFolderPath(Environment.SpecialFolder.InternetCache) + @"\" + targetFile.Substring(targetFile.LastIndexOf(@"\") + 1);
            
            Stream writeStream = File.Create(tempLocation);

            int Length = 32768;
            Byte[] buffer = new Byte[Length];

            int bytesRead = readStream.Read(buffer, 0, Length);
            while (bytesRead > 0)
            {
                writeStream.Write(buffer, 0, bytesRead);
                bytesRead = readStream.Read(buffer, 0, Length);
            }

            writeStream.Close();
            readStream.Close();

            _Callback(new UpdateData(EventType.ItemUpdate, photoTitle, ImageStatus.Downloaded));

            File.Move(tempLocation, targetFile);
        }

        protected static string GetImageSavePath(string _SaveLocation, string Title)
        {
            System.Text.StringBuilder filePath =new StringBuilder(Title + ".jpg");
            foreach (char InvalidChar in System.IO.Path.GetInvalidFileNameChars())
            {
                filePath.Replace(InvalidChar, '_');
            }

            return System.IO.Path.Combine(_SaveLocation, filePath.ToString());
        }
    }
}
